/**
 @file ctc_linkagg_cli.c

 @date 2020-06-23

 @version v1.0

---file comments----
*/

/****************************************************************
 *
 * Header Files
 *
 ***************************************************************/
#include "sal.h"
#include "ctc_cli.h"
#include "ctc_cli_common.h"
#include "api/include/ctcs_api.h"
#include "ctc_common.h"
#include "ctc_asw_common.h"
#define CTC_CLI_GPHYPORT_ID_DESC "type(4bit)|reserve(10bit)|lport_ext(3bit) | gchip(7bit, 0x1F for linkagg) | lport/linkagg_id (8bit)"
#define CTC_CLI_LINKAGG_ID_DESC "Linkagg id value"

CTC_CLI(ctc_cli_asw_linkagg_add_or_remove_port,
        ctc_cli_asw_linkagg_add_or_remove_port_cmd,
        "linkagg AGG_ID (add | remove) member-port GPHYPORT_ID",
        CTC_CLI_LINKAGG_M_STR,
        CTC_CLI_LINKAGG_ID_DESC,
        "Add member port to linkagg group",
        "Remove member port from linkagg group",
        "Member-port, global port",
        CTC_CLI_GPHYPORT_ID_DESC)
{
    int32 ret = CLI_SUCCESS;
    uint8 tid = 0;
    uint16 gport = 0;

    CTC_CLI_GET_UINT8("linkagg ", tid, argv[0]);
    CTC_CLI_GET_UINT16("gport", gport, argv[2]);


    if (0 == sal_memcmp("ad", argv[1], 2))
    {
        ret = ctcs_linkagg_add_port(g_api_lchip, tid, gport);
    }
    else if (0 == sal_memcmp("re", argv[1], 2))
    {
        ret = ctcs_linkagg_remove_port(g_api_lchip, tid, gport);
    }

    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s\n", ret, ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return ret;
}



CTC_CLI(ctc_cli_asw_parser_set_linkagg_hash,
        ctc_cli_asw_parser_set_linkagg_hash_cmd,
        "linkagg-hash {l2 {vlan|cos|ethertype|double-vlan|macsa|macda|port|}|\
        ip {l3protocol|ipsa|ipda|dscp|ipv6-flow-label|ecn|}|\
        l4 {l4-type|l4-user-type|src-port|dst-port|tcp-flag|tcp-ecn|gre-key|nvgre-vsid|nvgre-flow-id|vxlan-vni|vxlan-src-port|}|\
        pbb {b-vlan|b-cos|b-cfi|b-macsa|b-macda|isid|}|\
        mpls {m-l3protocol|m-ipsa|m-ipda|cancel-label|}|\
        fcoe {sid|did|}|\
        trill {ingress-nickname|egress-nickname|}|\
        common deviceinfo| udf udf-id UDF_ID bitmap VALUE} (inner|) (l2-only|)",
        "Linkagg hash field",
        "Layer2 ethernet",
        "Add vlan into linkagg hash",
        "Add cos into linkagg hash",
        "Add ethertype into linkagg hash",
        "Add double vlan into linkagg hash",
        "Add macsa into linkagg hash",
        "Add macda into linkagg hash",
        "Add global port into linkagg hash",
        "Layer3 ip",
        "Add l3protocol into linkagg hash",
        "Add ipsa into linkagg hash",
        "Add ipda into linkagg hash",
        "Add dscp into linkagg hash",
        "Add ipv6 flow label into linkagg hash",
        "Add ecn into linkagg hash",
        "Layer4",
        "Add layer4 type into linkagg hash",
        "Add layer4 user type into linkagg hash",
        "Add layer4 src port into linkagghash",
        "Add dst port into linkagg hash",
        "Add tcp flag into linkagg flag",
        "Add tcp ecn into linkagg flag",
        "Add gre key into linkagg hash",
        "Add nvgre vsid into linkagg hash",
        "Add nvgre flow id into linkagg hash",
        "Add vxlan vni into linkagg hash",
        "Add vxlan src port into linkagg hash",
        "Provider backbone",
        "Add bvlan into linkagg hash",
        "Add bcos into linkagg hash",
        "Add bcfi into linkagg hash",
        "Add bmacsa into linkagg hash",
        "Add bmacda into linkagg hash",
        "Add isid into linkagg hash",
        "Mpls",
        "Add mpls l3protocol into linkagg hash",
        "Add mpls ipsa into linkagg hash",
        "Add mpls ipda into linkagg hash",
        "Cancel mpls label from linkagg hash",
        "Fcoe",
        "Add sid into linkagg hash",
        "Add did into linkagg hash",
        "Trill",
        "Add ingress nickname into linkagg hash",
        "Add egress nickname into linkagg hash",
        "Common",
        "Add deviceinfo into linkagg hash",
        "Udf",
        "UDF ID",
        "Value",
        "Value",
        "Value",
        "Inner",
        "L2 only")
{
    int32 ret = 0;
    uint32 pre_index = 0;
    ctc_linkagg_psc_t linkagg_hash_ctl;

    sal_memset(&linkagg_hash_ctl, 0, sizeof(ctc_linkagg_psc_t));

    pre_index = CTC_CLI_GET_ARGC_INDEX("l2");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.psc_type_bitmap |= CTC_LINKAGG_PSC_TYPE_L2;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ethertype");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.l2_flag |= CTC_LINKAGG_PSC_L2_ETHERTYPE;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("macsa");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.l2_flag |= CTC_LINKAGG_PSC_L2_MACSA;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("macda");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.l2_flag |= CTC_LINKAGG_PSC_L2_MACDA;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("port");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.l2_flag |= CTC_LINKAGG_PSC_L2_PORT;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ip");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.psc_type_bitmap |= CTC_LINKAGG_PSC_TYPE_IP;
    }


    pre_index = CTC_CLI_GET_ARGC_INDEX("l3protocol");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.ip_flag |= CTC_LINKAGG_PSC_IP_PROTOCOL;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ipsa");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.ip_flag |= CTC_LINKAGG_PSC_IP_IPSA;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ipda");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.ip_flag |= CTC_LINKAGG_PSC_IP_IPDA;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("l4");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.psc_type_bitmap |= CTC_LINKAGG_PSC_TYPE_L4;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("src-port");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.l4_flag |= CTC_LINKAGG_PSC_L4_SRC_PORT;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("dst-port");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.l4_flag |= CTC_LINKAGG_PSC_L4_DST_PORT;
    }
    ret = ctcs_linkagg_set_psc(g_api_lchip, &linkagg_hash_ctl);

    if (ret < 0)
    {
        ctc_cli_out("%% %s \n", ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    return CLI_SUCCESS;
}

CTC_CLI(ctc_cli_asw_linkagg_show_member_port,
        ctc_cli_asw_linkagg_show_member_port_cmd,
        "show linkagg AGG_ID member-ports",
        CTC_CLI_SHOW_STR,
        CTC_CLI_LINKAGG_M_STR,
        CTC_CLI_LINKAGG_ID_DESC,
        "Member ports of linkagg group")
{
    int32 ret = CLI_SUCCESS;
    uint16 cnt  = 0;
    uint16 idx = 0;
    uint8 tid = CTC_MAX_LINKAGG_GROUP_NUM;
    uint32* p_gports = NULL;

    CTC_CLI_GET_UINT8("linkagg id", tid, argv[0]);

    p_gports = (uint32*)mem_malloc(MEM_CLI_MODULE, sizeof(uint32) * (CTC_ASW_MAX_PHY_PORT+1));
    if (NULL == p_gports)
    {
        return CLI_ERROR;
    }

    sal_memset(p_gports, 0, sizeof(uint32) * (CTC_ASW_MAX_PHY_PORT+1));

    ret = ctcs_linkagg_get_member_ports(g_api_lchip, tid, p_gports, &cnt);
    if (ret < 0)
    {
        ctc_cli_out("%% ret = %d, %s\n", ret, ctc_get_error_desc(ret));
        mem_free(p_gports);
        return CLI_ERROR;
    }

    ctc_cli_out("%-11s%s\n", "No.", "Member-Gport");
    ctc_cli_out("----------------------\n");

    for (idx = 0; idx < cnt; idx++)
    {
        ctc_cli_out("%-11u0x%04X\n", idx + 1, p_gports[idx]);
    }

    mem_free(p_gports);
    p_gports = NULL;

    return ret;
}

CTC_CLI(ctc_cli_asw_parser_show_linkagg_hash,
        ctc_cli_asw_parser_show_linkagg_hash_cmd,
        "show linkagg-hash {l2 {ethertype|double-vlan|macsa|macda|port}|\
        ip {use-ip|l3protocol|ipsa|ipda|dscp|ipv6-flow-label|ecn}|\
        l4 {use-l4|l4-type|l4-user-type|src-port|dst-port|tcp-flag|tcp-ecn|gre-key|nvgre-vsid|nvgre-flow-id|vxlan-vni|vxlan-src-port}|",
        CTC_CLI_SHOW_STR,
        "Linkagg hash field",
        "Layer2 ethernet",
        "Add ethertype into linkagg hash",
        "Add double vlan into linkagg hash",
        "Add macsa into linkagg hash",
        "Add macda into linkagg hash",
        "Add global port into linkagg hash",
        "Layer3 ip",
        "Use ip hash",
        "Add l3protocol into linkagg hash",
        "Add ipsa into linkagg hash",
        "Add ipda into linkagg hash",
        "Add dscp into linkagg hash",
        "Add ipv6 flow label into linkagg hash",
        "Add ecn into linkagg hash",
        "Layer4",
        "Use layer4 hash",
        "Add layer4 type into linkagg hash",
        "Add layer4 user type into ecmp hash",
        "Add src port into linkagg hash",
        "Add dst port into linkagg hash",
        "Add tcp flag into linkagg hash",
        "Add tcp ecn into linkagg hash",
        "Add gre key into linkagg hash",
        "Add nvgre vsid into linkagg hash",
        "Add nvgre flow id into linkagg hash",
        "Add vxlan vni into linkagg hash",
        "Add vxlan src port into linkagg hash")
{
    int32 ret = 0;
    uint32 pre_index = 0;
    ctc_linkagg_psc_t linkagg_hash_ctl;
    sal_memset(&linkagg_hash_ctl, 0, sizeof(ctc_linkagg_psc_t));

    pre_index = CTC_CLI_GET_ARGC_INDEX("l2");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.psc_type_bitmap |= CTC_LINKAGG_PSC_TYPE_L2;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ip");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.psc_type_bitmap |= CTC_LINKAGG_PSC_TYPE_IP;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("l4");
    if (0xFF != pre_index)
    {
        linkagg_hash_ctl.psc_type_bitmap |= CTC_LINKAGG_PSC_TYPE_L4;
    }
    ret = ctcs_linkagg_get_psc(g_api_lchip, &linkagg_hash_ctl);

    if (ret < 0)
    {
        ctc_cli_out("%% %s \n", ctc_get_error_desc(ret));
        return CLI_ERROR;
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ethertype");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.l2_flag) & CTC_LINKAGG_PSC_L2_ETHERTYPE)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("macsa");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.l2_flag) & CTC_LINKAGG_PSC_L2_MACSA)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("macda");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.l2_flag) & CTC_LINKAGG_PSC_L2_MACDA)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("port");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.l2_flag) & CTC_LINKAGG_PSC_L2_PORT)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("l3protocol");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.ip_flag) & CTC_LINKAGG_PSC_IP_PROTOCOL)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ipsa");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.ip_flag) & CTC_LINKAGG_PSC_IP_IPSA)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("ipda");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.ip_flag) & CTC_LINKAGG_PSC_IP_IPDA)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("src-port");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.l4_flag) & CTC_LINKAGG_PSC_L4_SRC_PORT)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    pre_index = CTC_CLI_GET_ARGC_INDEX("dst-port");
    if (0xFF != pre_index)
    {
        if ((linkagg_hash_ctl.l4_flag) & CTC_LINKAGG_PSC_L4_DST_PORT)
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "enable");
        }
        else
        {
            ctc_cli_out("%s : %s\n", argv[pre_index], "disable");
        }
    }

    return CLI_SUCCESS;
}

int32
ctc_asw_linkagg_cli_init(uint8 cli_tree_mode)
{
    install_element(cli_tree_mode, &ctc_cli_asw_linkagg_add_or_remove_port_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_parser_set_linkagg_hash_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_parser_show_linkagg_hash_cmd);
    install_element(cli_tree_mode, &ctc_cli_asw_linkagg_show_member_port_cmd);
    return 0;
}


